home *** CD-ROM | disk | FTP | other *** search
Wrap
/* File: FontMenuLibrary.c Contains: graphics libraries - gxFont menu library routines Written by: Cary Clark, Georgiann Delaney, Michael Fairman, Dave Good, Robert Johnson, Keith McGreggor, Mike Reed, Oliver Steele, David Van Brink, Chris Yerga Copyright: © 1995 by Apple Computer, Inc., all rights reserved. Change History (most recent first): <6> 6/26/95 TD remove local copy of FlipBack <5> 5/4/95 JD updating DelMenuItem to DeleteMenuItem <4> 4/7/95 jtd taking out all references to 'GestaltEqu.h' <3> 1/24/95 JD updated to latest GX 1.1 source (as of 16 Jan 1995) <2> 1/9/95 JD changed 'boolean' to 'Boolean' <1> 1/9/95 JD First checked in. */ #include <Resources.h> #include <Menus.h> #include <Memory.h> #include <ToolUtils.h> #include <Types.h> #include <Fonts.h> #include <Menus.h> #include <Gestalt.h> #include <GXTypes.h> #include <GXEnvironment.h> #include <GXGraphics.h> #include <GXLayout.h> #include <GXFonts.h> #include "FontMenuLibrary.h" #include "FontLibrary.h" #include "LayoutFeatureConstants.h" /* jtdfix - what are we doing here?? */ #if !defined(__powerc) pascal Handle XGetNextFOND(Handle fontHandle) = {0x700A, 0xA822}; /* this disappeared in the latest release of THINK C */ #else #define XGetNextFOND GetNextFOND #endif /***************************************** * Menu manager library routines to handle fonts * *****************************************/ void DeleteMenuItems(MenuHandle menuH) { int i; for (i = CountMenuItems(menuH); i > 0; --i) DeleteMenuItem(menuH, i); } static long AppendMenuName(MenuHandle menu, long length, unsigned char name[]) { name[0] = length < 255 ? length : 255; AppendMenu(menu, (const unsigned char *) "\pfont name"); /*** some full names disable the item */ /* cast for Think C 4.0 */ SetMenuItemText(menu, CountMenuItems(menu), name); return length > 255; } static MenuHandle NewMenuName(short menuID, long length, unsigned char *title) { Str255 str; str[0] = length < 255 ? length : 255; BlockMove(title+1, &str[1], str[0]); return NewMenu(menuID, str); } static int Str255Compare(Str255 a, Str255 b) { int i, minSize = a[0] < b[0] ? a[0] : b[0]; for (i = 1; i < minSize; i++) { if (a[i] == b[i]) continue; return a[i] - b[i]; } return a[0] - b[0]; } /* * sorts the text, command char, and item mark * this way any submenus will sort with the item * THIS SHOULD CALL SOME COOL INTL. SORT ROUTINE */ void SortMenu(MenuHandle menu) { short i, j, count = CountMenuItems(menu); for (i = 2; i <= count; i++) for (j = count; j >= i; --j) { short lowercmdChar, uppercmdChar; short lowermarkChar, uppermarkChar; Str255 lower, upper; GetMenuItemText(menu, j, lower); GetMenuItemText(menu, j-1, upper); GetItemCmd ( menu, j, &lowercmdChar ); GetItemCmd ( menu, j-1, &uppercmdChar ); GetItemMark ( menu, j, &lowermarkChar ); GetItemMark ( menu, j-1, &uppermarkChar ); if (Str255Compare(lower, upper) < 0) { SetMenuItemText(menu, j, upper); SetMenuItemText(menu, j-1, lower); SetItemCmd ( menu, j, uppercmdChar ); SetItemCmd ( menu, j-1, lowercmdChar ); SetItemMark ( menu, j, uppermarkChar ); SetItemMark ( menu, j-1, lowermarkChar ); } } } /* * Append a menu with the fonts' full names */ long FontMenu(MenuHandle menu) { return FontPlatformMenu(menu, gxNoPlatform, gxNoScript, gxNoLanguage); } /* * Append a menu with the fonts' full names for fonts that support the specified platform */ long FontPlatformMenu(MenuHandle menu, gxFontPlatform platform, gxFontScript script, gxFontLanguage language) { gxFont* fonts; long i, count, nameIndex; count = GXFindFonts(nil, 0, platform, script, language, 0, nil, 1, gxSelectToEnd, 0); fonts = (gxFont*)NewPtr(count * sizeof(gxFont)); GXFindFonts(nil, 0, platform, script, language, 0, nil, 1, count, fonts); for (i = 0; i < count; i++) { unsigned char *name; long length; if ((length = GXFindFontName(fonts[i], gxFullFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, &nameIndex)) > 0) { name = (unsigned char *) NewPtr(length + 1); GXGetFontName(fonts[i], nameIndex, nil, nil, nil, nil, &name[1]); AppendMenuName(menu, length, name); DisposePtr((Ptr) name); } } DisposePtr((Ptr)fonts); SortMenu(menu); return count; } /* * Append a menu with the fonts' family names */ long FontFamilyMenu(MenuHandle menu) { return FontFamilyPlatformMenu(menu, gxNoPlatform, gxNoScript, gxNoLanguage); } long FontFamilyPlatformMenu(MenuHandle menu, gxFontPlatform platform, gxFontScript script, gxFontLanguage language) { gxFont* fonts; long i, count; count = GXFindFonts(nil, gxFamilyFontName, platform, script, language, 0, nil, 1, gxSelectToEnd, nil); fonts = (gxFont*)NewPtr(count * sizeof(gxFont)); GXFindFonts(nil, gxFamilyFontName, platform, script, language, 0, nil, 1, count, fonts); for (i = 0; i < count; i++) { unsigned char name[256]; name[0] = GXFindFontName(fonts[i], gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil); if (name[0]) AppendMenuName(menu, name[0], name); } DisposePtr((Ptr)fonts); SortMenu(menu); return count; } /* * Create a menu with the given gxFont family's name, filled with the styles available in that family */ MenuHandle FontStyleMenu(short menuID, gxFont family) { long i, count = CountFontStyles(family); long length; MenuHandle menu; unsigned char *name; if ((length = GXFindFontName(family, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) { name = (unsigned char *) NewPtr(length + 1); GXFindFontName(family, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil); menu = NewMenuName(menuID, length, name); DisposePtr((Ptr) name); } else menu = NewMenu(menuID, (unsigned char *) "\pNo family name"); /* cast for Think C 4.0 */ for (i = 1; i <= count; i++) { gxFont sfnt = FindFontStyle(family, i, 0, 0, 0, 0, nil); if ((length = GXFindFontName(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) { name = (unsigned char *) NewPtr(length + 1); GXFindFontName(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil); AppendMenuName(menu, length, name); DisposePtr((Ptr)name); } } SortMenu(menu); return menu; } /*********************************************/ /* HierFontMenu */ /* */ /* the firstHierMenuID let's the application decide */ /* what number the heir menu IDs start */ /* */ /*********************************************/ short HierFontMenu(MenuHandle theMenu, short firstHierMenuID, fontFilterProc proc, fontMenuAttribute attr) { long i, count; short heirsUsed = 0; long howManyInstances; long howManyVariations; gxFontVariation *variations; gxFontName fontNameID; count = GXFindFonts(nil, 0, 0, 0, 0, 0, nil, 1, gxSelectToEnd, 0); for (i = 1; i <= count; i++) { gxFont fontID; long length; GXFindFonts(nil, 0, 0, 0, 0, 0, nil, i, 1, &fontID); if (proc && !proc(fontID)) continue; length = GXFindFontName(fontID, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil); if (length) { unsigned char *name; Boolean alreadyInMenu = false; short numMItem; short k; name = (unsigned char *) NewPtr(length + 1); GXFindFontName(fontID, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil); numMItem = CountMenuItems(theMenu);/*how many items have i already added to the menu*/ for (k=1; k<= numMItem; k++) /*check to see if the name is already in the menu*/ { Str255 str; GetMenuItemText (theMenu, k, str); name[0] = length; /*fake str255*/ if ( !Str255Compare(str, name) ) alreadyInMenu = true; } if (!alreadyInMenu) /*if not then add it*/ { MenuHandle hMenu; AppendMenuName(theMenu, length, name); hMenu = FontStyleMenu(heirsUsed + firstHierMenuID, fontID); howManyInstances = (attr & noInstancesFontMenu) ? 0 : GXCountFontInstances(fontID); if( ( (CountMenuItems(hMenu)) > 1) || (howManyInstances > 0) )/*only add it if it is more than one item*/ { InsertMenu (hMenu, -1); SetItemCmd(theMenu, numMItem+1, hMenuCmd); SetItemMark(theMenu, numMItem+1, heirsUsed + firstHierMenuID); heirsUsed ++; } if(howManyInstances) { short m; howManyVariations = GXCountFontVariations(fontID); variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations); AppendMenu(hMenu, (const unsigned char *) "\p(-" ); /*dotted gxLine*/ for(m = 1; m<=howManyInstances; m++) { DisposePtr((Ptr) name); fontNameID = GXGetFontInstance(fontID, m, variations); if ((length = GXFindFontName(fontID, fontNameID, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) { name = (unsigned char *) NewPtr(length+1); GXFindFontName(fontID, fontNameID, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil); AppendMenuName(hMenu, length, name); } } } } DisposePtr((Ptr) name); } } SortMenu(theMenu); return(heirsUsed); } gxFont DoHierFontMenuCommand(long menuResult, short hierFontMenuID, long *instanceIndex) { short theItem = LoWord (menuResult); short theMenuID = HiWord (menuResult); gxFont fontID = nil; Str255 str; *instanceIndex = 0; if (theMenuID == hierFontMenuID) { GetMenuItemText(GetMenuHandle(theMenuID), theItem, str); GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1, &fontID); if (GXFindFonts(fontID, gxFamilyFontName, gxNoPlatform, gxNoScript, gxNoLanguage, 0, nil, 1, gxSelectToEnd, nil) > 1) GXFindFonts(fontID, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, 7, (unsigned char*)"Regular", 1,1, &fontID); } else if ((theMenuID > 0) && (theMenuID < 235)) /* range of hierarchial submenus && assume owner is hierfontMenuID */ { MenuHandle mh; long index; mh = GetMenuHandle(theMenuID); BlockMove ( (**mh).menuData, str, (**mh).menuData[0]+1 ); /*the title of gxStyle menu is the family name*/ GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1, &fontID); index = theItem - (CountMenuItems( mh ) - GXCountFontInstances(fontID)) ; if (index > 0) /*it's an instance*/ *instanceIndex = index; else { GetMenuItemText(mh, theItem, str); GXFindFonts(fontID, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1, &fontID); } } HiliteMenu (0); return fontID; } Boolean DoHierFontMenuCommandStyle(long menuResult, short hierFontMenuID, gxStyle aStyle, long matchInfo) { short theItem = LoWord (menuResult); short theMenuID = HiWord (menuResult); gxFont sfnt; Boolean success = true; long instanceIndex; if (sfnt = DoHierFontMenuCommand(menuResult, hierFontMenuID, &instanceIndex)) { if (matchInfo && ((theMenuID == hierFontMenuID) || (theItem == 0))) /*theItem was on the family name*/ SetMatchingStyle(sfnt, aStyle, matchInfo); else /*no gxStyle matching*/ { GXSetStyleFont(aStyle, sfnt); if (instanceIndex) { long howManyVariations; gxFontVariation* variations; howManyVariations = GXCountFontVariations(sfnt); variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations); if (variations == nil) goto FAILURE; GXGetFontInstance(sfnt, instanceIndex, variations); GXSetStyleFont(aStyle, sfnt); GXSetStyleFontVariations(aStyle, howManyVariations, variations); DisposePtr((Ptr)variations); } else GXSetStyleFontVariations(aStyle, 0, nil); } } else /*not our menu*/ FAILURE: success = false; HiliteMenu (0); return(success); } short DoHierFontMenuCommandShape(long menuResult, short hierFontMenuID,gxShape aShape) { short theItem = LoWord (menuResult); short theMenuID = HiWord (menuResult); gxFont sfnt; short success = true; long instanceIndex; sfnt = DoHierFontMenuCommand(menuResult, hierFontMenuID, &instanceIndex); if (sfnt) { GXSetShapeFont(aShape, sfnt); if(instanceIndex) { long howManyVariations; gxFontVariation *variations; howManyVariations = GXCountFontVariations(sfnt); variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations); GXGetFontInstance(sfnt, instanceIndex, variations); GXSetShapeFont(aShape, sfnt); GXSetShapeFontVariations(aShape, howManyVariations, variations); DisposePtr((Ptr)variations); } else GXSetShapeFontVariations(aShape, 0, nil); } else /*not our menu*/ success = false; HiliteMenu (0); return(success); } long FontToQD(gxFont fontID, long* styleBits) { short resID, i, count; OSType resType; Str255 resName; Handle sfnt; if (GXGetFont(fontID, (gxFontStorageReference*)&sfnt, nil) != gxResourceFontStorage) goto NOT_FOUND; GetResInfo(sfnt, &resID, &resType, resName); if (ResError()) goto NOT_FOUND; count = CountResources('FOND'); for (i = 1; i <= count; i++) { Handle fond = GetIndResource('FOND', i); if (!ResError() && fond && *fond) do { short* sp = (short*)(*fond + sizeof(FamRec)); int entries = *sp++; for (; entries >= 0; --entries) { if (*sp == 0 && sp[2] == resID) { if (styleBits) *styleBits = sp[1]; GetResInfo(fond, &resID, &resType, resName); return resID; } sp += 3; /* three elements in the FAT */ } } while ((fond = XGetNextFOND(fond)) != 0); } NOT_FOUND: return 0; } /*************** font features *************/ long GetMenuRunFeatures(MenuHandle menu, gxFont fontID, gxRunFeature feature[]) { long i, featureCount, item, count; count = 0; item = 1; featureCount = GXCountFontFeatures(fontID); for (i = 1; i <= featureCount; i++) { long settingCount, j; gxFontFeature featureType; gxFontFeatureSetting* settings; GXGetFontFeature(fontID, i, nil, &settingCount, nil, &featureType); settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting)); GXGetFontFeature(fontID, i, nil, nil, settings, nil); for (j = 0; j < settingCount; j++) { short mark; GetItemMark(menu, item, &mark); if (mark) { if (feature) { feature[count].featureType = featureType; feature[count].featureSelector = settings[j].setting; } ++count; } ++item; } DisposePtr((Ptr)settings); if (i < featureCount) ++item; /* skip the underline */ } return count; } static Boolean SearchRunFeatures(long count, const gxRunFeature feature[], gxFontFeature featureType, long featureSetting) { if (count) { const gxRunFeature *stop = feature + count; do { if (feature->featureType == featureType && feature->featureSelector == featureSetting) return true; ++feature; } while (feature < stop); } return false; } void SetMenuRunFeatures(MenuHandle menu, gxFont fontID, long count, const gxRunFeature feature[]) { long i, featureCount, item; item = 1; featureCount = GXCountFontFeatures(fontID); for (i = 1; i <= featureCount; i++) { long settingCount, j; gxFontFeature featureType; gxFontFeatureSetting* settings; GXGetFontFeature(fontID, i, nil, &settingCount, nil, &featureType); settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting)); GXGetFontFeature(fontID, i, nil, nil, settings, nil); for (j = 0; j < settingCount; j++) { CheckItem(menu, item, SearchRunFeatures(count, feature, featureType, settings[j].setting)); ++item; } DisposePtr((Ptr)settings); if (i < featureCount) ++item; /* skip the underline */ } } static gxRunFeature* CopyDefaultFeatures(gxFont fontID, long* featureCount) { long count; gxRunFeature* feature = nil; if (count = GetDefaultFontFeatures(fontID, nil)) if (feature = (gxRunFeature*)NewPtr(count * sizeof(gxRunFeature))) GetDefaultFontFeatures(fontID, feature); else count = 0; if (featureCount) *featureCount = count; return feature; } void FontFeatureMenu(MenuHandle menu, gxFont fontID) { long i, featureCount; Str255 name; DeleteMenuItems(menu); featureCount = GXCountFontFeatures(fontID); for (i = 1; i <= featureCount; i++) { long settingCount, j; gxFontFeatureSetting* settings; GXGetFontFeature(fontID, i, nil, &settingCount, nil, nil); settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting)); GXGetFontFeature(fontID, i, nil, nil, settings, nil); for (j = 0; j < settingCount; j++) { FindFontPName(fontID, settings[j].nameID, name); AppendMenu(menu, name); } DisposePtr((Ptr)settings); if (i < featureCount) AppendMenu(menu, "\p(-"); } } void ToggleFeatureMenuItem(MenuHandle menuH, gxFont fontID, long item) { long i, currItem, featureCount; featureCount = GXCountFontFeatures(fontID); currItem = 1; for (i = 1; i <= featureCount; i++) { long settingCount; gxFontFeatureFlag flag; GXGetFontFeature(fontID, i, &flag, &settingCount, nil, nil); if (item < currItem + settingCount) { short mark; GetItemMark(menuH, item, &mark); if (flag & gxMutuallyExclusiveFeature) { if (mark == noMark) for (i = currItem; i < currItem + settingCount; i++) CheckItem(menuH, i, i == item); } else CheckItem(menuH, item, mark == noMark); break; } currItem += settingCount + 1; /* +1 to skip the dashed divider */ } } void ToggleFeatureMenuFeature(MenuHandle menuH, gxFont fontID, gxRunFeature feature) { int currItem = 1; long i, j, featureCount = GXCountFontFeatures(fontID); for (i = 1; i <= featureCount; i++) { long settingCount; gxFontFeatureFlag flag; gxFontFeature featureType; GXGetFontFeature(fontID, i, &flag, &settingCount, nil, &featureType); if (feature.featureType == featureType) { gxFontFeatureSetting* settings; if (settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting))) { GXGetFontFeature(fontID, i, nil, nil, settings, nil); for (j = 0; j < settingCount; j++) if (settings[j].setting == feature.featureSelector) { short mark, item = currItem + j; GetItemMark(menuH, item, &mark); if (flag & gxMutuallyExclusiveFeature) { if (mark == noMark) for (j = currItem; j < currItem + settingCount; j++) CheckItem(menuH, j, j == item); } else CheckItem(menuH, item, mark == noMark); break; } DisposePtr((Ptr)settings); } break; } currItem += settingCount + 1; /* +1 to skip the dashed divider */ } } void StyleFeatureMenu(MenuHandle menuH, const gxStyle style) { gxFont fontID = GXGetStyleFont(style); long featureCount = GXGetStyleRunFeatures(style, nil); FontFeatureMenu(menuH, fontID); if (featureCount) { gxRunFeature* feature = (gxRunFeature*)NewPtr(featureCount * sizeof(gxRunFeature)); if (feature) { GXGetStyleRunFeatures(style, feature); SetMenuRunFeatures(menuH, fontID, featureCount, feature); DisposePtr((Ptr)feature); } } } typedef struct { unsigned long defaultFlags; /* The default sub-feature flags for this chain. */ unsigned long chainLength; /* The length of the chain in bytes, including this header. */ unsigned short nFeatureEntries; /* The number of entries in the chain's feature table. */ unsigned short nSubtables; /* The number of subtables in the chain. */ } ChainHeader; typedef struct { Fixed version; /* Version number of the glyph metamorphosis table (0x00010000 for the initial version. */ unsigned long nChains; /* Number of metamorphosis chains which follow. */ } MortHeader; typedef struct { unsigned short featureType; unsigned short featureSetting; unsigned long enableFlags; /* Flags for sub-features this feature and setting enables. */ unsigned long disableFlags; /* Complement of flags for sub-features this feature and setting disables. */ } FeatureTableEntry; /* * GetFontDefaultFeatures returns a list of features and settings that are on by default in the specified font. * This routine will be added to the next GX Font Manager, as the format for the 'mort' table may change in the future. */ long GetDefaultFontFeatures(gxFont fontID, gxRunFeature features[]) { #define kGXVersionWhenDefaultFeaturesWasAdded 0x00010100 long mortIndex, defaultFeatureCount; long response; Gestalt(gestaltGraphicsVersion, &response); if (response >= kGXVersionWhenDefaultFeaturesWasAdded) return GXGetFontDefaultFeatures(fontID, features); defaultFeatureCount = 0; if (GXFindFontTable(fontID, 'mort', nil, &mortIndex)) { MortHeader* mortHead; ChainHeader* chainHead; long size, chainCount; size = GXGetFontTable(fontID, mortIndex, nil, nil); mortHead = (MortHeader*)NewPtr(size); if (mortHead == nil) return 0; defaultFeatureCount = 1; if (features) { features->featureType = allTypographicFeaturesType; features->featureSelector = allTypeFeaturesOnSelector; ++features; } GXGetFontTable(fontID, mortIndex, mortHead, nil); chainCount = mortHead->nChains; chainHead = (ChainHeader*)(mortHead + 1); while (chainCount--) { if (chainHead->nFeatureEntries) { unsigned long defaultFlags; FeatureTableEntry* featureEntry; int featureCount; defaultFlags = chainHead->defaultFlags; featureEntry = (FeatureTableEntry*)(chainHead + 1); featureCount = chainHead->nFeatureEntries; while (featureCount--) { if (featureEntry->enableFlags & defaultFlags) { if (features) { features->featureType = featureEntry->featureType; features->featureSelector = featureEntry->featureSetting; ++features; } ++defaultFeatureCount; } ++featureEntry; } } chainHead = (ChainHeader*)((char*)chainHead + chainHead->chainLength); } DisposePtr((Ptr)mortHead); } return defaultFeatureCount; } void SetShapeDefaultFeatures(gxShape dst, gxFont fontID) { long featureCount; gxRunFeature* feature; feature = CopyDefaultFeatures(fontID, &featureCount); GXIgnoreGraphicsNotice(attributes_already_set); GXSetShapeRunFeatures(dst, featureCount, feature); GXPopGraphicsNotice(); if (feature) DisposePtr((Ptr)feature); } void SetStyleDefaultFeatures(gxStyle dst, gxFont fontID) { long featureCount; gxRunFeature* feature; feature = CopyDefaultFeatures(fontID, &featureCount); GXIgnoreGraphicsNotice(attributes_already_set); GXSetStyleRunFeatures(dst, featureCount, feature); GXPopGraphicsNotice(); if (feature) DisposePtr((Ptr)feature); }